home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Frameworks / Hsoi's App Shell 1.0a4 / HAS Other Source / WASTE 1.3a4 Distribution / WASTE 1.3a4 / Source / WEInlineInput.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-16  |  17.9 KB  |  763 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    WEInlineInput.c
  3.  *
  4.  *    WASTE PROJECT
  5.  *  Inline Input Support
  6.  *
  7.  *  Copyright (c) 1993-1997 Marco Piovanelli
  8.  *    All Rights Reserved
  9.  *
  10.  *  C port by Dan Crevier
  11.  *
  12.  */
  13.  
  14.  
  15. #include "WASTEIntf.h"
  16.  
  17. // special event ID used by Kotoeri and other input methods
  18.  
  19. enum
  20. {
  21.     kGetText = 'gtxt'
  22. };
  23.  
  24. // static variables
  25.  
  26. static AEEventHandlerUPP _weUpdateActiveInputAreaHandler = nil;
  27. static AEEventHandlerUPP _wePositionToOffsetHandler = nil;
  28. static AEEventHandlerUPP _weOffsetToPositionHandler = nil;
  29. static AEEventHandlerUPP _weGetTextHandler = nil;
  30.  
  31. pascal OSErr _WEHiliteRangeArray(TextRangeArrayHandle hTray, WEHandle hWE)
  32. {
  33.     WEPtr pWE = *hWE;    // assume WE record is already locked
  34.     TextRangePtr pRange;
  35.     SInt32 rangeStart, rangeEnd;
  36.     SInt16 hiliteStyle;
  37.     WETextStyle ts;
  38.     SInt16 rangeIndex;
  39.     Boolean saveTrayLock;
  40.     OSErr err;
  41.  
  42.     // lock down the range array
  43.     saveTrayLock = _WESetHandleLock((Handle)hTray, true);
  44.     pRange = (*hTray)->fRange;
  45.  
  46.     // walk the hilite range array
  47.     for (rangeIndex = (*hTray)->fNumOfRanges - 1; rangeIndex >= 0; rangeIndex-- )
  48.     {
  49.  
  50.         // the offsets in the range array are relative to the beginning
  51.         // of the active input area: convert them to absolute offsets
  52.         rangeStart = pWE->tsmAreaStart + pRange->fStart;
  53.         rangeEnd = pWE->tsmAreaStart + pRange->fEnd;
  54.         hiliteStyle = pRange->fHiliteStyle;
  55.  
  56.         // take the absolute value of hiliteStyle
  57.         hiliteStyle = ABS(hiliteStyle);
  58.  
  59.         // if hiliteStyle is kCaretPosition, set the selection range
  60.         if (hiliteStyle == kCaretPosition)
  61.         {
  62.             pWE->selStart = rangeStart;
  63.             pWE->selEnd = rangeEnd;
  64.         }
  65.         else
  66.         {
  67.             hiliteStyle -= kRawText;
  68.             // otherwise set the WETextStyle flags of the specified range appropriately
  69.             if ((hiliteStyle >= 0) && (hiliteStyle <= 3))
  70.             {
  71.                 ts.tsFlags = 0x10 + (hiliteStyle << tsTSMSelected);
  72.                 if ((err = _WESetStyleRange(rangeStart, rangeEnd, weDoFlags, &ts, hWE)) != noErr)
  73.                 {
  74.                     goto cleanup;
  75.                 }
  76.             }
  77.         }
  78.         // go to next text range element
  79.         pRange++;
  80.     }
  81.  
  82.     // clear result code
  83.     err = noErr;
  84.  
  85. cleanup:
  86.     // unlock the range array
  87.     _WESetHandleLock((Handle)hTray, saveTrayLock);
  88.  
  89.     return err;
  90. }
  91.  
  92. static pascal OSErr _WEHandleUpdateActiveInputArea(const AppleEvent *ae, AppleEvent *reply, SInt32 handlerRefCon)
  93. {
  94. #pragma unused(reply, handlerRefCon)
  95.     WEHandle hWE = nil;
  96.     WEPtr pWE;
  97.     AEDesc text;
  98.     AEDesc hiliteTray;
  99.     TextRange pinRange;
  100.     SInt32 totalLength;
  101.     SInt32 fixLength;
  102.     SInt32 tsmOffset;
  103.     DescType actualType;
  104.     SInt32 actualSize;
  105.     GrafPtr savePort;
  106.     WEActionHandle hAction;
  107.     Boolean saveAutoScroll;
  108.     Boolean saveTextLock;
  109.     Boolean saveWELock = false;
  110.     OSErr err;
  111.  
  112.     // initialize descriptors to null values
  113.     text.descriptorType = typeNull;
  114.     text.dataHandle = nil;
  115.     hiliteTray.descriptorType = typeNull;
  116.     hiliteTray.dataHandle = nil;
  117.  
  118.     // extract WE handle
  119.     if ((err = AEGetParamPtr(ae, keyAETSMDocumentRefcon, typeLongInteger,
  120.             &actualType, &hWE, sizeof(hWE), &actualSize)) != noErr)
  121.     {
  122.         goto cleanup;
  123.     }
  124.  
  125.     // lock the WE handle
  126.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  127.     pWE = *hWE;
  128.  
  129.     // return an error code if this instance is read-only
  130.     err = weReadOnlyErr;
  131.     if (BTST(pWE->features, weFReadOnly))
  132.     {
  133.         goto cleanup;
  134.     }
  135.  
  136.     // call the pre-update callback, if present
  137.     if (pWE->tsmPreUpdate != nil)
  138.     {
  139.         CallWETSMPreUpdateProc(hWE, pWE->tsmPreUpdate);
  140.     }
  141.  
  142.     // hide the caret if it's showing
  143.     if (BTST(pWE->flags, weFCaretVisible))
  144.     {
  145.         _WEBlinkCaret(hWE);
  146.     }
  147.  
  148.     // extract the text descriptor
  149.     if ((err = AEGetParamDesc(ae, keyAETheData, typeChar, &text)) != noErr)
  150.     {
  151.         goto cleanup;
  152.     }
  153.  
  154.     // get total length of text in the active input area
  155.     totalLength = GetHandleSize(text.dataHandle);
  156.  
  157.     // extract the length of confirmed text in the active input area
  158.     if ((err = AEGetParamPtr(ae, keyAEFixLength, typeLongInteger, &actualType,
  159.             &fixLength, sizeof(fixLength), &actualSize)) != noErr)
  160.     {
  161.         goto cleanup;
  162.     }
  163.  
  164.     // if fixLength = -1, all text is confirmed
  165.     if (fixLength == -1)
  166.     {
  167.         fixLength = totalLength;
  168.     }
  169.  
  170.     // if there's currently no active input area, open one
  171.     if (pWE->tsmAreaStart == kInvalidOffset)
  172.     {
  173.         pWE->tsmAreaStart = pWE->selStart;
  174.         pWE->tsmAreaEnd = pWE->selEnd;
  175.  
  176.         // are we tracking a typing sequence?
  177.         if (!WEIsTyping(hWE))
  178.         {
  179.             // nope; so start a new one
  180.             // increment modification count
  181.             pWE->modCount++;
  182.  
  183.             // if undo support is enabled, the inline session just started may initiate
  184.             if (BTST(pWE->features, weFUndoSupport))
  185.             {
  186.                 WEClearUndo(hWE);
  187.                 if (_WENewAction(pWE->selStart, pWE->selEnd, 0, weAKTyping, 0, hWE, &hAction) == noErr)
  188.                 {
  189.                     _WEPushAction(hAction);
  190.                 }
  191.             }
  192.         }
  193.     }
  194.  
  195.     tsmOffset = pWE->tsmAreaStart;
  196.  
  197.     // the new text replaces whatever is in the active input area
  198.     if ((err = _WEDeleteRange(tsmOffset, pWE->tsmAreaEnd, hWE)) != noErr)
  199.     {
  200.         goto cleanup;
  201.     }
  202.  
  203.     // synchronize the null style, so font script matches the keyboard script
  204.     _WESynchNullStyle(hWE);
  205.  
  206.     // set the port font for good measure
  207.     GetPort(&savePort);
  208.     SetPort(pWE->port);
  209.     TextFont(pWE->nullStyle.runStyle.tsFont);
  210.     SetPort(savePort);
  211.  
  212.     // insert the text
  213.     saveTextLock = _WESetHandleLock(text.dataHandle, true);
  214.     err = _WEInsertText(tsmOffset, *(text.dataHandle), totalLength, hWE);
  215.     _WESetHandleLock(text.dataHandle, saveTextLock);
  216.     if (err != noErr)
  217.     {
  218.         goto cleanup;
  219.     }
  220.  
  221.     // extract pin range
  222.     if ((err = AEGetParamPtr(ae, keyAEPinRange, typeTextRange, &actualType,
  223.             &pinRange, sizeof(pinRange), &actualSize)) == noErr)
  224.     {
  225.         // we want absolute offsets
  226.         pinRange.fStart += tsmOffset;
  227.         pinRange.fEnd += tsmOffset;
  228.     }
  229.     else
  230.     {
  231.         // a missing pin range descriptor isn't an error; everything else is
  232.         if (err != errAEDescNotFound)
  233.         {
  234.             goto cleanup;
  235.         }
  236.  
  237.         // default pin range is active input area
  238.         pinRange.fStart = tsmOffset;
  239.         pinRange.fEnd = pWE->tsmAreaEnd;
  240.     }
  241.  
  242.     // NOTE: if fixLength == totalLength, the inline input session is over, so, in theory,
  243.     // hiliteTray should either be missing or not specify any range to be underlined.
  244.     // Unfortunately, some input methods (like Apple's input method for Simplified Chinese)
  245.     // do specify kConvertedText (= thin black underline) for the whole text when
  246.     // the text is confirmed (is this a bug?).  To work around this, we deliberately ignore
  247.     // the hiliteTray parameter when fixLength = totalLength.
  248.  
  249.     if (fixLength != totalLength)
  250.     {
  251.         pWE->tsmAreaStart += fixLength;  // added by Kiyoshi Gomasaki for ATOK compatibility
  252.  
  253.         // extract the highlight range array
  254.         if ((err = AEGetParamDesc(ae, keyAEHiliteRange, typeTextRangeArray, &hiliteTray)) != noErr)
  255.         {
  256.             if (err != errAEDescNotFound)
  257.             {
  258.                 goto cleanup;
  259.             }
  260.         }
  261.     }
  262.  
  263.     if (hiliteTray.dataHandle != nil)
  264.     {
  265.         if ((err = _WEHiliteRangeArray((TextRangeArrayHandle) hiliteTray.dataHandle, hWE)) != noErr)
  266.         {
  267.             goto cleanup;
  268.         }
  269.     }
  270.     else
  271.     {
  272.         pWE->selStart = tsmOffset + fixLength;
  273.         pWE->selEnd = pWE->selStart;
  274.     }
  275.  
  276.     // temporarily disable auto-scroll, as we need to scroll manually according to pinRange
  277.     saveAutoScroll = BTST(pWE->features, weFAutoScroll) ? true : false;
  278.     BCLR(pWE->features, weFAutoScroll);
  279.  
  280.     // redraw the active input area
  281.     if ((err = _WERedraw(tsmOffset, tsmOffset + totalLength, hWE)) != noErr)
  282.     {
  283.         goto cleanup;
  284.     }
  285.  
  286.     if (saveAutoScroll)
  287.     {
  288.  
  289.         // re-enable auto-scroll
  290.         BSET(pWE->features, weFAutoScroll);
  291.  
  292.         // scroll the pin range into view
  293.         if (!_WEScrollIntoView(pinRange.fStart, hWE))
  294.         {
  295.             if (pinRange.fStart != pinRange.fEnd)
  296.             {
  297.                 _WEScrollIntoView(pinRange.fEnd, hWE);
  298.             }
  299.         }
  300.     }
  301.  
  302.     // update the boundaries of the active input area
  303.     // if fixLength = totalLength, the inline input session is over: close the active input area
  304.     if (fixLength == totalLength)
  305.     {
  306.         pWE->tsmAreaStart = kInvalidOffset;
  307.         pWE->tsmAreaEnd = kInvalidOffset;
  308.  
  309.         // adjust undo buffer (if any) for the confirmed text
  310.         _WEAdjustUndoRange(fixLength, hWE);
  311.     }
  312.     else
  313.     {
  314.         // otherwise, fixLength defines the boundaries of the active input area
  315.         pWE->tsmAreaStart = tsmOffset + fixLength;
  316.         pWE->tsmAreaEnd = tsmOffset + totalLength;
  317.     }
  318.  
  319.     // call the post-update callback, if present
  320.     if (pWE->tsmPostUpdate != nil)
  321.     {
  322.         CallWETSMPostUpdateProc(hWE, fixLength, pWE->tsmAreaStart, pWE->tsmAreaEnd,
  323.             pinRange.fStart, pinRange.fEnd, pWE->tsmPostUpdate);
  324.     }
  325.  
  326.     // clear result code
  327.     err = noErr;
  328.  
  329. cleanup:
  330.     // clean up
  331.     AEDisposeDesc(&text);
  332.     AEDisposeDesc(&hiliteTray);
  333.  
  334.     // unlock the WE record
  335.     if (hWE !=nil)
  336.     {
  337.         _WESetHandleLock((Handle) hWE, saveWELock);
  338.     }
  339.  
  340.     // return result code
  341.     return err;
  342. }
  343.  
  344. static pascal OSErr _WEHandlePositionToOffset(const AppleEvent *ae, AppleEvent *reply, SInt32 handlerRefCon)
  345. {
  346. #pragma unused(handlerRefCon)
  347.     WEHandle hWE = nil;
  348.     WEPtr pWE;
  349.     Point position;
  350.     LongPt thePoint;
  351.     SInt16 regionClass;
  352.     SInt32 offset;
  353.     DescType actualType;
  354.     SInt32 actualSize;
  355.     GrafPtr savePort;
  356.     WEEdge edge;
  357.     Boolean saveWELock = false;
  358.     OSErr err;
  359.  
  360.     // extract WE handle
  361.     if ((err = AEGetParamPtr(ae, keyAETSMDocumentRefcon, typeLongInteger,
  362.             &actualType, &hWE, sizeof(hWE), &actualSize)) != noErr)
  363.     {
  364.         goto cleanup;
  365.     }
  366.  
  367.     // lock the WE record
  368.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  369.     pWE = *hWE;
  370.  
  371.     // extract position parameter
  372.     if ((err = AEGetParamPtr(ae, keyAECurrentPoint, typeQDPoint, &actualType, &position, sizeof(position), &actualSize)) != noErr)
  373.     {
  374.             goto cleanup;
  375.     }
  376.  
  377.     // convert position to local...
  378.     GetPort(&savePort);
  379.     SetPort(pWE->port);
  380.     GlobalToLocal(&position);
  381.     SetPort(savePort);
  382.  
  383.     // ...and long coordinates
  384.     WEPointToLongPoint(position, &thePoint);
  385.  
  386.     // find the byte offset and the edge value corresponding to the given position
  387.     offset = WEGetOffset(&thePoint, &edge, hWE);
  388.  
  389.     // determine the region class
  390.     if (WELongPointInLongRect(&thePoint, &pWE->viewRect))
  391.     {
  392.         if (_WEOffsetInRange(offset, edge, pWE->tsmAreaStart, pWE->tsmAreaEnd))
  393.         {
  394.               regionClass = kTSMInsideOfActiveInputArea;
  395.             // if the given position is within the active input area, we're supposed to return
  396.             // an offset relative to the beginning of this area (thanks, Martin!)
  397.             offset -= pWE->tsmAreaStart;
  398.         }
  399.         else
  400.         {
  401.             // otherwise the offset is relative to the beginning of the body
  402.             regionClass = kTSMInsideOfBody;
  403.         }
  404.     }
  405.     else
  406.     {
  407.         regionClass = kTSMOutsideOfBody;
  408.     }
  409.  
  410.     // add region class parameter to reply
  411.     if ((err = AEPutParamPtr(reply, keyAERegionClass, typeShortInteger, ®ionClass, sizeof(regionClass))) != noErr)
  412.     {
  413.         goto cleanup;
  414.     }
  415.  
  416.     // add offset parameter to reply
  417.     if ((err = AEPutParamPtr(reply, keyAEOffset, typeLongInteger, &offset, sizeof(offset))) != noErr)
  418.     {
  419.         goto cleanup;
  420.     }
  421.  
  422.     // add edge parameter to reply
  423.     if ((err = AEPutParamPtr(reply, keyAELeftSide, typeBoolean, &edge, sizeof(edge))) != noErr)
  424.     {
  425.         goto cleanup;
  426.     }
  427.  
  428.     // clear result code
  429.     err = noErr;
  430.  
  431. cleanup:
  432.     // unlock the WE record
  433.     if (hWE != nil)
  434.     {
  435.         _WESetHandleLock((Handle) hWE, saveWELock);
  436.     }
  437.  
  438.     // return result code
  439.     return err;
  440. }
  441.  
  442. static pascal OSErr _WEHandleOffsetToPosition(const AppleEvent *ae, AppleEvent *reply, SInt32 handlerRefCon)
  443. {
  444. #pragma unused(handlerRefCon)
  445.     WEHandle hWE = nil;
  446.     WEPtr pWE;
  447.     SInt32 offset;
  448.     LongPt thePoint;
  449.     Point position;
  450.     SInt16 lineHeight;
  451.     DescType actualType;
  452.     SInt32 actualSize;
  453.     GrafPtr savePort;
  454.     Boolean saveWELock = false;
  455.     OSErr err;
  456.  
  457.     // extract WE handle
  458.     if ((err = AEGetParamPtr(ae, keyAETSMDocumentRefcon, typeLongInteger,
  459.             &actualType, &hWE, sizeof(hWE), &actualSize)) != noErr)
  460.     {
  461.         goto cleanup;
  462.     }
  463.  
  464.     // lock the WE record
  465.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  466.     pWE = *hWE;
  467.  
  468.     // if there's no active input area, return errOffsetInvalid
  469.     err = errOffsetInvalid;
  470.     if (pWE->tsmAreaStart < 0)
  471.     {
  472.         goto cleanup;
  473.     }
  474.  
  475.     // extract the offset parameter
  476.     if ((err = AEGetParamPtr(ae, keyAEOffset, typeLongInteger, &actualType, &offset, sizeof(offset), &actualSize)) != noErr)
  477.     {
  478.         goto cleanup;
  479.     }
  480.  
  481.     // offset is relative to the beginning of the active input area; we want an absolute offset
  482.     offset += pWE->tsmAreaStart;
  483.  
  484.     // make sure the offset is within the input area
  485.     if ((offset < pWE->tsmAreaStart) || (offset >= pWE->tsmAreaEnd))
  486.     {
  487.         err = errOffsetInvalid;
  488.         goto cleanup;
  489.     }
  490.  
  491.     // find the position corresponding to the given offset (in long coordinates)
  492.     WEGetPoint(offset, hilite, &thePoint, &lineHeight, hWE);
  493.     thePoint.v += lineHeight;
  494.  
  495.     // make sure offset is within view rectangle
  496.     if (!WELongPointInLongRect(&thePoint, &pWE->viewRect))
  497.     {
  498.         err = errOffsetIsOutsideOfView;
  499.         goto cleanup;
  500.     }
  501.  
  502.     // convert the point to short...
  503.     WELongPointToPoint(&thePoint, &position);
  504.  
  505.     // ...and global coordinates
  506.     GetPort(&savePort);
  507.     SetPort(pWE->port);
  508.     LocalToGlobal(&position);
  509.     SetPort(savePort);
  510.  
  511.     // add keyAEPoint parameter to the reply Apple event
  512.     if ((err = AEPutParamPtr(reply, keyAEPoint, typeQDPoint,
  513.             &position, sizeof(position))) != noErr)
  514.     {
  515.         goto cleanup;
  516.     }
  517.  
  518.     // add keyAETSMTextFont parameter to the reply Apple event
  519.     if ((err = AEPutParamPtr(reply, keyAETSMTextFont, typeShortInteger,
  520.             &pWE->nullStyle.runStyle.tsFont, sizeof(pWE->nullStyle.runStyle.tsFont))) != noErr)
  521.     {
  522.         goto cleanup;
  523.     }
  524.  
  525.     // add keyAETSMTextPointSize parameter to the reply Apple event
  526.     if ((err = AEPutParamPtr(reply, keyAETSMTextPointSize, typeShortInteger,
  527.             &pWE->nullStyle.runStyle.tsSize, sizeof(pWE->nullStyle.runStyle.tsSize))) != noErr)
  528.     {
  529.         goto cleanup;
  530.     }
  531.  
  532.     // add keyAETextLineAscent parameter to the reply Apple event
  533.     if ((err = AEPutParamPtr(reply, keyAETextLineAscent, typeShortInteger,
  534.             &pWE->nullStyle.runAscent, sizeof(pWE->nullStyle.runAscent))) != noErr)
  535.     {
  536.         goto cleanup;
  537.     }
  538.  
  539.     // add keyAETextLineHeight parameter to the reply Apple event
  540.     if ((err = AEPutParamPtr(reply, keyAETextLineHeight, typeShortInteger,
  541.             &pWE->nullStyle.runHeight, sizeof(pWE->nullStyle.runHeight))) != noErr)
  542.     {
  543.         goto cleanup;
  544.     }
  545.  
  546.     // clear result code
  547.     err = noErr;
  548.  
  549. cleanup:
  550.     // unlock the WE record
  551.     if (hWE != nil)
  552.     {
  553.         _WESetHandleLock((Handle) hWE, saveWELock);
  554.     }
  555.  
  556.     // return result code
  557.     return err;
  558. }
  559.  
  560. static pascal OSErr _WEHandleGetText(const AppleEvent *ae, AppleEvent *reply, SInt32 handlerRefCon)
  561. {
  562. #pragma unused(handlerRefCon)
  563.  
  564.     WEHandle hWE = nil;
  565.     WEPtr pWE;
  566.     DescType actualType;
  567.     SInt32 actualSize;
  568.     Boolean saveWELock = false;
  569.     Boolean saveTextLock;
  570.     OSErr err;
  571.  
  572.     // extract WE handle
  573.     if ((err = AEGetParamPtr(ae, keyAETSMDocumentRefcon, typeLongInteger,
  574.             &actualType, &hWE, sizeof(hWE), &actualSize)) != noErr)
  575.     {
  576.         goto cleanup;
  577.     }
  578.  
  579.     // lock the WE record
  580.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  581.     pWE = *hWE;
  582.  
  583.     // return a copy of the selected text in the reply event
  584.     saveTextLock = _WESetHandleLock(pWE->hText, true);
  585.     err = AEPutParamPtr(reply, keyAETheData, typeText,
  586.             *pWE->hText + pWE->selStart, pWE->selEnd - pWE->selStart);
  587.     _WESetHandleLock(pWE->hText, saveTextLock);
  588.     if (err != noErr)
  589.     {
  590.         goto cleanup;
  591.     }
  592.  
  593.     // clear result code
  594.     err = noErr;
  595.  
  596. cleanup:
  597.     // unlock the WE record
  598.     if (hWE != nil)
  599.     {
  600.         _WESetHandleLock((Handle) hWE, saveWELock);
  601.     }
  602.  
  603.     // return result code
  604.     return err;
  605. }
  606.  
  607. pascal OSErr WEInstallTSMHandlers(void)
  608. {
  609.     OSErr err;
  610.  
  611.     // the first time we're called, create routine descriptors for our Apple event handlers
  612.     if (_weUpdateActiveInputAreaHandler == nil)
  613.     {
  614.         _weUpdateActiveInputAreaHandler = NewAEEventHandlerProc(_WEHandleUpdateActiveInputArea);
  615.         _wePositionToOffsetHandler = NewAEEventHandlerProc(_WEHandlePositionToOffset);
  616.         _weOffsetToPositionHandler = NewAEEventHandlerProc(_WEHandleOffsetToPosition);
  617.         _weGetTextHandler = NewAEEventHandlerProc(_WEHandleGetText);
  618.     }
  619.  
  620.     // install Apple Event handlers to be used by Text Service components
  621.     if ((err = AEInstallEventHandler(kTextServiceClass, kUpdateActiveInputArea, _weUpdateActiveInputAreaHandler, 0, false)) != noErr)
  622.     {
  623.         goto cleanup;
  624.     }
  625.  
  626.     if ((err = AEInstallEventHandler(kTextServiceClass, kPos2Offset, _wePositionToOffsetHandler, 0, false)) != noErr)
  627.     {
  628.         goto cleanup;
  629.     }
  630.  
  631.     if ((err = AEInstallEventHandler(kTextServiceClass, kOffset2Pos, _weOffsetToPositionHandler, 0, false)) != noErr)
  632.     {
  633.         goto cleanup;
  634.     }
  635.  
  636.     if ((err = AEInstallEventHandler(kTextServiceClass, kGetText, _weGetTextHandler, 0, false)) != noErr)
  637.     {
  638.         goto cleanup;
  639.     }
  640.  
  641.     // clear result code
  642.     err = noErr;
  643.  
  644. cleanup:
  645.     // return result code
  646.     return err;
  647. }
  648.  
  649. pascal OSErr WERemoveTSMHandlers(void)
  650. {
  651.     OSErr err;
  652.  
  653.     // return an error code if WEInstallTSMHandlers has never been called
  654.     if (_weUpdateActiveInputAreaHandler == nil)
  655.     {
  656.         return errAEHandlerNotFound;
  657.     }
  658.  
  659.     // remove the handlers
  660.     if ((err = AERemoveEventHandler(kTextServiceClass, kUpdateActiveInputArea, _weUpdateActiveInputAreaHandler, false)) != noErr)
  661.     {
  662.         goto cleanup;
  663.     }
  664.  
  665.     if ((err = AERemoveEventHandler(kTextServiceClass, kPos2Offset, _wePositionToOffsetHandler, false)) != noErr)
  666.     {
  667.         goto cleanup;
  668.     }
  669.  
  670.     if ((err = AERemoveEventHandler(kTextServiceClass, kOffset2Pos, _weOffsetToPositionHandler, false)) != noErr)
  671.     {
  672.         goto cleanup;
  673.     }
  674.  
  675.     if ((err = AERemoveEventHandler(kTextServiceClass, kGetText, _weGetTextHandler, false)) != noErr)
  676.     {
  677.         goto cleanup;
  678.     }
  679.  
  680.     // clear result code
  681.     err = noErr;
  682.  
  683. cleanup:
  684.     // clear result code
  685.     return err;
  686.  
  687. }
  688.  
  689. pascal OSErr WEHandleTSMEvent(const AppleEvent *ae, AppleEvent *reply)
  690. {
  691.     AEEventClass eventClass;
  692.     AEEventID eventID;
  693.     DescType actualType;
  694.     Size actualSize;
  695.     OSErr err;
  696.  
  697.     //    get event class
  698.     if ((err = AEGetAttributePtr(ae, keyEventClassAttr, typeType, &actualType, &eventClass, sizeof(eventClass), &actualSize)) != noErr)
  699.     {
  700.         goto cleanup;
  701.     }
  702.  
  703.     //    make sure the event class is kTextServiceClass
  704.     err = errAEEventNotHandled;
  705.     if (eventClass != kTextServiceClass)
  706.     {
  707.         goto cleanup;
  708.     }
  709.  
  710.     //    get event ID
  711.     if ((err = AEGetAttributePtr(ae, keyEventIDAttr, typeType, &actualType, &eventID, sizeof(eventID), &actualSize)) != noErr)
  712.     {
  713.         goto cleanup;
  714.     }
  715.  
  716.     //    dispatch to appropriate handler
  717.     switch (eventID)
  718.     {
  719.         case kUpdateActiveInputArea:
  720.         {
  721.             err = _WEHandleUpdateActiveInputArea(ae, reply, 0);
  722.             break;
  723.         }
  724.  
  725.         case kPos2Offset:
  726.         {
  727.             err = _WEHandlePositionToOffset(ae, reply, 0);
  728.             break;
  729.         }
  730.  
  731.         case kOffset2Pos:
  732.         {
  733.             err = _WEHandleOffsetToPosition(ae, reply, 0);
  734.             break;
  735.         }
  736.  
  737.         case kGetText:
  738.         {
  739.             err = _WEHandleGetText(ae, reply, 0);
  740.             break;
  741.         }
  742.  
  743.         default:
  744.         {
  745.             break;
  746.         }
  747.     }
  748.  
  749. cleanup:
  750.     return err;
  751. }
  752.  
  753. pascal void WEStopInlineSession(WEHandle hWE)
  754. {
  755.     WEPtr pWE = *hWE;
  756.  
  757.     // call FixTSMDocument() only if the inline input area is actually "open"
  758.     if ((pWE->tsmAreaStart != kInvalidOffset) && (pWE->tsmReference != nil))
  759.     {
  760.         FixTSMDocument(pWE->tsmReference);
  761.     }
  762. }
  763.